/*
 * Copyright 2008 Max Kugland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.splink.asbeangen.parser;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import com.wutka.dtd.DTD;
import com.wutka.dtd.DTDAttribute;
import com.wutka.dtd.DTDCardinal;
import com.wutka.dtd.DTDChoice;
import com.wutka.dtd.DTDDecl;
import com.wutka.dtd.DTDElement;
import com.wutka.dtd.DTDItem;
import com.wutka.dtd.DTDMixed;
import com.wutka.dtd.DTDName;
import com.wutka.dtd.DTDPCData;
import com.wutka.dtd.DTDSequence;

/**
 * Helper class
 * 
 * @author maxmc
 *
 */
public class ParseTools {
	protected static boolean isArray(String cardinal) {
		return (cardinal.equals("+") || cardinal.equals("*"));
	}

	protected static List<DTDItem> getChoice(DTDItem item) {
		List<DTDItem> v = new ArrayList<DTDItem>();
		if (item instanceof DTDChoice) {
			DTDItem[] items = ((DTDChoice) item).getItems();
			for (int i = 0; i < items.length; i++) {
				v.add(items[i]);
			}
			return v;
		}
		return v;
	}

	protected static List<DTDItem> getSequence(DTDItem item) {
		List<DTDItem> v = new ArrayList<DTDItem>();
		if (item instanceof DTDSequence) {
			DTDItem[] items = ((DTDSequence) item).getItems();
			for (int i = 0; i < items.length; i++) {
				v.add(items[i]);
			}
			return v;
		}
		return v;
	}

	protected static List<DTDItem> getMixed(DTDItem item) {
		List<DTDItem> v = new ArrayList<DTDItem>();
		if (item instanceof DTDMixed) {
			DTDItem[] items = ((DTDMixed) item).getItems();
			for (int i = 0; i < items.length; i++) {
				if (!(items[i] instanceof DTDPCData))
					v.add(items[i]);
			}
			return v;
		}
		return v;
	}

	protected static DTDPCData getPcData(DTDItem item) {
		if (item instanceof DTDMixed) {
			DTDItem[] items = ((DTDMixed) item).getItems();
			for (int i = 0; i < items.length; i++) {
				if (items[i] instanceof DTDPCData) {
					return ((DTDPCData) items[i]);
				}
			}
		}
		return null;
	}

	protected static String getCardinal(DTDItem item) {
		if (item.cardinal == DTDCardinal.OPTIONAL) {
			return "?";
		} else if (item.cardinal == DTDCardinal.ZEROMANY) {
			return "*";
		} else if (item.cardinal == DTDCardinal.ONEMANY) {
			return "+";
		} else
			return "";
	}
	
	/**
	 * Checks whether a given DTDAttribute is implied or required.
	 * 
	 * @param the DTDAttribute to check
	 * @return true if given DTDAttribute is implied, otherwise false
	 */
	protected static boolean getIsImplied(DTDAttribute at) {
		if (at.decl != null) {
			return (at.decl == DTDDecl.IMPLIED);
		}
		return false;
	}
	
	/**
	 * Returns the name of an DTDItem, if no name can be detected, an empty String
	 * is returned.
	 * 
	 * @param item the DTDItem whose name is returned
	 * @return the name of the DTDItem
	 */
	protected static String getName(DTDItem item) {
		if (item instanceof DTDName) {
			return clean(((DTDName) item).value);
		}
		return "";
	}
	
	/**
	 * Cleans node names, so they can't contain '-' or '_' chars
	 * @param name the original node name
	 * @return the cleaned node name
	 */
	protected static String clean(String name) {
		return name.replace("-", "").replace("_", "");
	}

	/**
	 * Collect single elements without childs and attributes but a #PCDATA  
	 * This reduces the amount of generated classes, because those single #PCDATA
	 * elements become member of the parent class.
	 * 
	 * @return a list of String representing the node names of the collected #PCDATA elements
	 */
	protected static List<String> getPCDElements(DTD dtd) {
		List<String> ignore = new ArrayList<String>(); 
		
		List<String> pcdElems = new ArrayList<String>();
		Enumeration<?> elements = dtd.elements.elements();
		while (elements.hasMoreElements()) {
			DTDElement elem = (DTDElement) elements.nextElement();
			String name = clean(elem.name);
			
			// ignore sequences
			ignore.addAll(getNames(getMixed(elem.content)));
			ignore.addAll(getNames(getSequence(elem.content)));
			

			if (elem.attributes.isEmpty() && getPcData(elem.content) != null) {
//				List<DTDItem> found = getMixed(elem.content);
//				if (found.size() < 1)
//					found = getSequence(elem.content);
//				if (found.size() < 1)
//					found = getChoice(elem.content);
				
				
//				if (found.size() < 1) {
				if(!ignore.contains(elem.name)) {
					pcdElems.add(name);
				}
			}
		}
		return pcdElems;
	}

	private static List<String> getNames(List<DTDItem> items) {
		List<String> list = new ArrayList<String>();
		for (DTDItem dtdItem : items) {
			String name = getName(dtdItem);
			if(!name.equals("")) {
				list.add(name);
			}
		}
		return list;
	}
}